<?php
/**
 * Nweb Framework
 *
 * This script is protected by copyright. It's use, copying, modification
 * and distribution without written consent of the author is prohibited.
 *
 * @category    source
 * @package     pl.nweb.framework.view
 * @author      Krzysztof Kardasz <krzysztof.kardasz@gmail.com>
 * @copyright   Copyright (c) 2011 Krzysztof Kardasz
 * @license     http://www.gnu.org/licenses/lgpl-3.0.txt  GNU Lesser General Public
 * @version     3.0 $Id$
 * @link        http://code.google.com/p/nweb-framework/
 * @link        http://framework.nweb.pl
 */

namespace pl\nweb\framework\view;

/**
 * Szablon
 *
 * @category    source
 * @package     pl.nweb.framework.view
 * @author      Krzysztof Kardasz <krzysztof.kardasz@gmail.com>
 * @copyright   Copyright (c) 2011 Krzysztof Kardasz
 * @version     3.0 $Id$
 */
class Template
{
    /**
     * Dane
     * 
     * @var array
     */
    private $_data = array();
    
    /**
     * Ścieżki plików widoku
     * 
     * @var array
     */
    private $_paths = array();
    
    /**
     * Plik widoku
     * 
     * @var string
     */
    private $_file = null;
    
    /**
     * Zawartość
     * 
     * @var string
     */
    private $_contents = null;
    
    /**
     * Flaga, włączone generowanie widoku
     * 
     * @var boolean
     */
    private $_enabled = true;

    /**
     * Obiekt menadżera pomocników
     *
     * @var \pl\nweb\framework\view\helper\Broker
     */
    private $_helper_broker = null;

    /**
     * Obiekt menadżera filtrów
     *
     * @var \pl\nweb\framework\view\filter\Broker
     */
    private $_filter_broker = null;
    
    /**
    * Definuje wartość zmiennej widoku
    *
    * @param  string $name nazwa
    * @param  string $value wartość
    * @return void
    */
    public function __set ($name, $value)
    {
        $this->set($name, $value);
    }
    
    /**
     * Zwraca wartość zmiennej widoku
     *
     * @param  string $name nazwa zmiennej
     * @return mixed
     */
    public function __get ($name)
    {
        return $this->get($name);
    }
    
    /**
     * Zwraca flagę czy zmienna widoku istnieje
     *
     * @param  string $name nazwa zmiennej
     * @return boolean
     */
    public function __isset ($name)
    {
        return $this->has($name);
    }
    
    /**
     * Definiuje flagę czy generowanie widoku jest włączone
     *
     * @param boolean $flag flaga
     * @return void
     */
    public function setEnabled ($flag = true)
    {
        $this->_enabled = (boolean)$flag;
    }
    
    /**
     * Definiowanie wartości
     *
     * @param string|array $key  klucz lub tablica wartości
     * @param null|string $value wartość
     * @return void
     */
    public function set ($key, $value = null)
    {
        if(is_array($key)) {
            $this->_data = array_merge($this->_data, $key);
        } else {
            $this->_data[$key] = $value;
        }
    }
    
    /**
     * Zwraca wartość
     *
     * @param string $key  klucz lub tablica wartości
     * @param mixed $default domyślna wartość
     * @return mixed
     */
    public function get ($key, $default = null)
    {
        if(isset($this->_data[$key])) {
            return $this->_data[$key];
        }
        return $default;
    }
    
    /**
     * Zwraca flagę czy wartość została zdefiniowana
     *
     * @param string $key  klucz lub tablica wartości
     * @return boolean
     */
    public function has ($key)
    {
        return isset($this->_data[$key]);
    }
    
    /**
     * Zwraca flagę czy wartość jest taka jak wartość porównawcza
     *
     * @param string $key  klucz lub tablica wartości
     * @param mixed $value wartość do porównania
     * @return boolean
     */
    public function is ($key, $value)
    {
        return isset($this->_data[$key]) && $this->_data[$key] == $value;
    }
    
    /**
    * Definiuje obiekt pośrednika pomocników widoku
    *
    * @param \pl\nweb\framework\view\helper\Broker $obj obiekt
    * @return void
    */
    public function setHelperBroker (\pl\nweb\framework\view\helper\Broker $obj)
    {
        $this->_helper_broker = $obj;
    }
    
    /**
    * Zwraca obiekt pośrednika pomocników widoku
    *
    * @return \pl\nweb\framework\view\helper\Broker
     * @throws \pl\nweb\framework\view\Exception
    */
    public function getHelperBroker ()
    {
        if(null === $this->_helper_broker) {
            throw new Exception ('Helper broker object is not defined!');
        }
        return $this->_helper_broker;
    }
    
    /**
     * Definiuje obiekt pośrednika filtrów
     *
     * @param \pl\nweb\framework\view\filter\Broker $obj obiekt
     */
    public function setFilterBroker (\pl\nweb\framework\view\filter\Broker $obj)
    {
        $this->_filter_broker = $obj;
    }
    
    /**
     * Zwraca obiekt pośrednika filtrów
     *
     * @return \pl\nweb\framework\view\filter\Broker
     * @throws \pl\nweb\framework\view\Exception
     */
    public function getFilterBroker ()
    {
        if(null === $this->_filter_broker) {
            throw new Exception ('Filter broker object is not defined!');
        }
        return $this->_filter_broker;
    }
    
    /**
    * Wywołanie filtra
    *
    * @param  string $name|null  nazwa filtru
    * @param  mixed $value|null filtrowana wartość
    * @return \pl\nweb\framework\view\filter\Broker|\pl\nweb\framework\Filter|mixed
    */
    public function filter ($name = null, $value = null)
    {
        if($name !== null && $value !== null) {
            return $this->getFilterBroker()->{$name}($value);
        } elseif($name !== null) {
            return $this->getFilterBroker()->{$name};
        } else {
            return $this->getFilterBroker();
        }
    }
    
    /**
     * Wywołanie pomocnika widoku
     *
     * @return \pl\nweb\framework\view\helper\Broker|\pl\nweb\framework\view\Helper|mixed
     */
    public function helper ()
    {
        $params = func_get_args();
        if(!empty($params)) {
            return call_user_func_array(array($this->getHelperBroker(), $params[0]), array_shift($params));
        } else {
            return $this->getHelperBroker();
        }
    }
    
    /**
     * Definiuje plik widoku
     *
     * @param  string $file plik
     * @return void
     */
    public function setFile ($file)
    {
        $this->_file = $file;
    }
    
    /**
     * Zwraca plik widoku
     *
     * @return null|string
     */
    public function getFile ()
    {
        return $this->_file;
    }
    
    /**
     * Dodanie ścieżki plików widoku
     *
     * @param  string $dir katalog filtrów
     * @throws \pl\nweb\framework\view\Exception
     */
    public function addPath ($dir)
    {
        if(!is_dir($dir)) {
            throw new Exception ('Directory "' . $dir . '" not exists or do not have permission');
        }
        array_unshift($this->_paths, $dir);
    }
    
    /**
     * Definiowanie zawartości
     *
     * @param string $contents zawartość
     * @return void
     */
    public function setContents ($contents)
    {
        $this->_contents = $contents;
    }
    
    /**
     * Wyczyszczenie zawartości
     *
     * @return void
     */
    public function clean ()
    {
        $this->_contents = null;
    }
    
    /**
     * Generowanie widoku
     *
     * @return null|string
     */
    public function render ()
    {
        if(!$this->_enabled) {
            return false;
        }
        if(null === $this->_contents) {
            if(empty($this->_paths)) {
                throw new Exception ('No view directory set');
            } elseif(empty($this->_file)) {
                throw new Exception ('No script file set');
            }
            
            $file = null;
            foreach($this->_paths as $path) {
                $tmp = $path . DIRECTORY_SEPARATOR . $this->_file;
                if(is_file($tmp)) {
                    ob_start();
                    include $file;
                    return $this->_content = ob_get_clean();
                }
            }
            throw new Exception ('View file "' . $this->_file . '" not found');
        }
        return $this->_contents;
    }
}